﻿using Autofac;
using Autofac.Builder;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;
using Autofac.Extras.DynamicProxy;
using Core.AppExtensions;
using Core.AutoFacService.Abstract;
using Core.AutoFacService.Attributes.InjectAttributes;
using Core.AutoFacService.Enums;
using Core.AutoFacService.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Core.AutoFacService
{
	public static class AutoFacExtensions
    {
        /// <summary>
        /// autofac接管控制器的生成
        /// </summary>
        /// <param name="services"></param>
        public static void AddAutoFacControllerService(this IServiceCollection services)
        {
            services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>());
        }
        /// <summary>
        /// 构造AutofacContainer接管MS自带的容器
        /// </summary>
        /// <param name="builder"></param>
        public static void RegisterContainer(this ContainerBuilder builder)
        {
            var dlls = App.GetDlls();
            List<Type> interfaceInjectList = new();
			List<Type> genericInterfaceInjectList = new List<Type>();
			List<Type> configList=new();
            List<Type> componentList=new();
            List<Type> interceptors = new();
			AutowiredPropertySelector autowiredPropertySelector= new AutowiredPropertySelector();
			ValuePropertySelector valuePropertySelector = new ValuePropertySelector();
			//扫描全部dll 把不同特性的type分出来
			foreach (var dll in dlls)
            {
                foreach(Type type in dll.GetTypes())
                {
                    if (!type.IsAbstract)
                    {
                        var interfaceInjectAttr = type.GetCustomAttribute<InjectAttribute>();
                        if (interfaceInjectAttr != null)
                        {
							if (type.IsGenericType)
							{
								genericInterfaceInjectList.Add(type);
							}
							else
							{
								interfaceInjectList.Add(type);
							}
                            
						}
                        if (type.GetCustomAttribute<ComponentAttribute>() != null)
                        {
							if (type.IsSubclassOf(typeof(AbstractInterceptor)))
							{
								interceptors.Add(type);
							}
                            else
                            {
								componentList.Add(type);
							}
							
                        }
                        if(type.GetCustomAttribute<ConfignatrueAttribute>() != null)
                        {
                            configList.Add(type);
                        }
                        
                    }
                }
            }
            var typeMapInterceptor = GetTypeMapInterceptor(interceptors);
			//注入拦截器
			foreach(Type type in interceptors.OrderBy(t=>t.GetCustomAttribute<ComponentAttribute>().Order).ThenBy(t=>t.Name))
			{
				builder.RegisterType(type)
					.PropertiesAutowired(autowiredPropertySelector)
					.PropertiesAutowired(valuePropertySelector)
					.AsSelf();
			}
			//注入组件
			foreach(Type type in componentList.OrderBy(t => t.GetCustomAttribute<ComponentAttribute>().Order).ThenBy(t => t.Name))
			{
				IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> register = builder.RegisterType(type);
				ComponentAttribute attr = type.GetCustomAttribute<ComponentAttribute>();
				switch (attr.Lifetime)
				{
					case LifetimeEnum.Scope:
						register = register.InstancePerLifetimeScope();
						break;
					case LifetimeEnum.Single:
						register = register.SingleInstance();
						break;
					case LifetimeEnum.Transient:
						register = register.InstancePerDependency();
						break;
				}
				register
					.PropertiesAutowired(autowiredPropertySelector)
					.PropertiesAutowired(valuePropertySelector)
					.AsSelf();
			}
			//注入泛型接口实例
			foreach (Type type in genericInterfaceInjectList.OrderBy(t => t.GetCustomAttribute<InjectAttribute>().Order).ThenBy(t => t.Name))
			{
				var register = builder.RegisterGeneric(type);
				InjectAttribute attr = type.GetCustomAttribute<InjectAttribute>();
				bool hasInterceptor = typeMapInterceptor.TryGetValue(type, out List<Type> typeInterceptors);
				switch (attr.Lifetime)
				{
					case LifetimeEnum.Scope:
						register = register.InstancePerLifetimeScope();
						break;
					case LifetimeEnum.Single:
						register = register.SingleInstance();
						break;
					case LifetimeEnum.Transient:
						register = register.InstancePerDependency();
						break;
				}
				if (hasInterceptor)
				{
					register = register.EnableInterfaceInterceptors().InterceptedBy(typeInterceptors.ToArray());
				}
				if (!string.IsNullOrEmpty(attr.Name))
				{
					register = register.Named(attr.Name, type);
				}
				register
					.PropertiesAutowired(autowiredPropertySelector)
					.PropertiesAutowired(valuePropertySelector)
					.AsImplementedInterfaces();
			}
			//注入接口实例(非泛型接口)
			foreach (Type type in interfaceInjectList.OrderBy(t => t.GetCustomAttribute<InjectAttribute>().Order).ThenBy(t => t.Name))
            {
				IRegistrationBuilder<object, ConcreteReflectionActivatorData, SingleRegistrationStyle> register = builder
					.RegisterType(type);
				InjectAttribute attr = type.GetCustomAttribute<InjectAttribute>();
				bool hasInterceptor = typeMapInterceptor.TryGetValue(type, out List<Type> typeInterceptors);
				switch (attr.Lifetime) 
                {
                    case LifetimeEnum.Scope:
						register = register.InstancePerLifetimeScope();
						break;
					case LifetimeEnum.Single:
						register= register.SingleInstance();
						break;
					case LifetimeEnum.Transient:
						register = register.InstancePerDependency();
						break;
				}
				if(hasInterceptor)
				{
					register = register.EnableInterfaceInterceptors().InterceptedBy(typeInterceptors.ToArray());
				}
				if (!string.IsNullOrEmpty(attr.Name))
				{
					register = register.Named(attr.Name, type);
				}
				register
					.PropertiesAutowired(autowiredPropertySelector)
					.PropertiesAutowired(valuePropertySelector)
					.AsImplementedInterfaces();
			}
			//注入配置实例
			foreach(Type type in configList) 
			{
				ConfignatrueAttribute confignatrue=type.GetCustomAttribute<ConfignatrueAttribute>();
				string path=confignatrue.Path;
				string fileName = confignatrue.SourceFile;
				string[] paths = path.Split(".");
				var config = AutoFacHelper.GetConfiguration(fileName);
				object value;
				foreach(string s in paths)
				{
					config = config.GetSection(s);
				}
				value = config.Get(type);
				builder.RegisterInstance(value).AsSelf();
			}
			builder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().AsImplementedInterfaces();
		}
        /// <summary>
        /// 获取哪些类型需要被拦截器拦截
        /// </summary>
        /// <param name="interceptors"></param>
        /// <returns></returns>
        private static Dictionary<Type, List<Type>> GetTypeMapInterceptor(IEnumerable<Type> interceptors)
        {
			Dictionary<Type, List<Type>> typeMapInterceptor = new();
			foreach (Type intercepterType in interceptors)
			{
				var constructor = intercepterType.GetConstructors()
				.Where(t => t.GetParameters().Select(a => a.ParameterType).Contains(typeof(IEnumerable<Assembly>)))
				.FirstOrDefault();
				if (constructor == null)
				{
					continue;
				}
				else
				{
					object[] paramtersArray = new object[constructor.GetParameters().Length];
					for (int i = 0; i < constructor.GetParameters().Length; i++)
					{
						if (constructor.GetParameters()[i].ParameterType == typeof(IEnumerable<Assembly>))
						{
							paramtersArray[i] = App.GetDlls();
						}
						else
						{
							paramtersArray[i] = AutoFacHelper.GetDefaultValue(constructor.GetParameters()[i].ParameterType);
						}

					}
					
					var obj = (AbstractInterceptor)constructor.Invoke(paramtersArray);
					var types = obj.GetInterceptorTypes();
					foreach (var type in types)
					{
						if (typeMapInterceptor.TryGetValue(type, out List<Type> result))
						{
							result.Add(intercepterType);
						}
						else
						{
							typeMapInterceptor.Add(type, new List<Type> { intercepterType });
						}
					}
				}
			}
			return typeMapInterceptor;
		}
		/// <summary>
		/// 接管容器
		/// </summary>
		/// <param name="builder"></param>
		/// <returns></returns>
		public static IHostBuilder UseAutoProviderFactory(this IHostBuilder builder)
        {
            return builder.UseServiceProviderFactory(new AutofacServiceProviderFactory());
        }

        public class AutowiredPropertySelector : IPropertySelector
        {
            public bool InjectProperty(PropertyInfo propertyInfo, object instance)
            {
                return propertyInfo.CustomAttributes.Any(t => t.AttributeType == typeof(AutowiredAttribute));
            }
        }

		public class ValuePropertySelector : IPropertySelector
		{
			public bool InjectProperty(PropertyInfo propertyInfo, object instance)
			{
				return propertyInfo.CustomAttributes.Any(t => t.AttributeType == typeof(ValueAttribute));
			}
		}

	}
}
